package com.meteor.framework.common.filter;

/**
 *
 *
 * @author lynn
 * @date 2024/1/12
 */

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 请求参数去除前后空格HttpServletRequestWrapper
 */
@Log4j2
public class ParameterTrimWrapper extends HttpServletRequestWrapper {

    //用于存放post请求体数据
    private byte[] body;

    //用于存放get请求参数
    private Map<String, String[]> params = new HashMap<>();

    private static final String CONTENT_TYPE = "Content-Type";

    private static final String GET = "GET";

    private static final String POST = "POST";

    public ParameterTrimWrapper(HttpServletRequest request) throws IOException {
        super(request);
        //处理get请求 url路径携带参数情况
        if(GET.equals(request.getMethod())){
            //获取到所有入参
            Map<String, String[]> requestMap = request.getParameterMap();
            if(ObjectUtil.isNotEmpty(requestMap)){
                this.params.putAll(requestMap);
                //对每个入参进行去除前后空格
                this.dealUrlParameter();
            }
        }
        //处理post请求 对请求体进行情况
        if(POST.equals(request.getMethod())){
            //getInputStream()读取请求体数据流
            String bodyJson = new String(IOUtils.toByteArray(super.getInputStream()), StandardCharsets.UTF_8);
            if(StringUtils.isNotEmpty(bodyJson)){
                //处理每个参数去除前后空格
                Map<String, Object> finalMap = dealJson(bodyJson);
                //将处理完的结果再次塞进body
                this.body = JSON.toJSONString(finalMap).getBytes(StandardCharsets.UTF_8);
            }
        }
    }

    /**
     * get请求参数处理 将参数中的值去除前后空格后写回
     */
    public void dealUrlParameter(){
        params.forEach((k,v) ->{
            for(int i = 0 ;i < v.length ; i++ ){
                v[i] = v[i].trim();
            }
            params.put(k,v);
        });
    }

    /**
     * post请求参数处理 处理json参数 去除前后空格
     * @param bodyJson json
     * @return map
     */
    public static Map<String, Object> dealJson(String bodyJson){
        Map<String, Object> jsonMap = new HashMap<>();
        //将body字符串转为json对象
        JSONObject jsonObject = JSONObject.parseObject(bodyJson);
        if (jsonObject != null) {
            //对键值对进行处理
            jsonObject.forEach((k,v) -> {
                //根据字段类型进行处理
                if(v instanceof JSONArray){
                    //如果第一层字段为数组，再对数组中每个元素类型判断递归处理
                    List<Object> list = new ArrayList<>();
                    for (Object obj : (JSONArray) v){
                        if(obj instanceof JSONObject){
                            list.add(dealJson(obj.toString()));
                        }else if(obj instanceof String){
                            list.add(obj.toString().trim());
                        }else {
                            list.add(obj);
                        }
                    }
                    jsonMap.put(k , list);
                }else if(v instanceof JSONObject){
                    //第一层字段为对象 对象内部进行递归处理
                    jsonMap.put(k , dealJson(v.toString()));
                }else if(v instanceof String){
                    //第一层字段为字符串 直接处理
                    jsonMap.put(k , v.toString().trim());
                }else {
                    //其他
                    jsonMap.put(k , v);
                }
            });
        }
        return jsonMap;
    }

    //重写getInputStream()，最后程序回来调用这个方法
    @Override
    public ServletInputStream getInputStream() throws IOException {
        //bais处理过后的最新数据流
        final ByteArrayInputStream bais =new ByteArrayInputStream(body);
        return new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {
            }

            @Override
            public int read() {
                return bais.read();
            }
        };

    }

    //已下几个方法是设计参数读写处理 照着写就行
    public String getBody() {
        return new String(this.body, StandardCharsets.UTF_8);
    }

    @Override
    public String[] getParameterValues(String name) {
        return params.get(name);
    }

    @Override
    public Map<String,String[]> getParameterMap(){
        return this.params;
    }

    @Override
    public String getParameter(String name) {
        String[]values = params.get(name);
        if(values == null || values.length == 0) {
            return null;
        }
        return values[0];
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }
}